/*
 * Copyright (c) Extreme Vision Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef EV_MODEL_ADAPTER_H
#define EV_MODEL_ADAPTER_H
#include <map>
#include <mutex>
#include <thread>
#include "evdeploy/core/ev_common_data.h"
#include "evdeploy/core/ev_model_base.h"

#ifdef ATLAS
#include "acl/acl.h"
#endif

namespace ev
{

struct ModelConfig
{
    std::string server_address;
    std::string mode;
    std::string type;
    std::string engine;
    std::string framework;
    std::string version;
    std::string model;
    std::vector<std::string> inputs;
    std::vector<std::string> outputs;
};

class EVBaseModel;
class EVBaseModelFactory;

class EVModelAdapter
{
    private:
        EVModelAdapter();
        EVModelAdapter(const EVModelAdapter&) = delete;
        EVModelAdapter &operator= (const EVModelAdapter&) = delete;
    public:
        /**
         * @brief adapter for creating one model
         * @param[in] uuid: create one model specified by the model uuid, complete model init will be done
         * @return false if some error occurs, e.g., the model file not exist, the runtime not supported.
         */
        bool CreateModel(const std::string& uuid);
        /**
         * @brief adapter for initializing model info
         * @param[in] config_file: config file name for model info
         * @return true if config file is right, else false
         */
        bool InitModel(const std::string& config_file);
        /**
         * @brief adapter for running inference
         * @param[in] uuid: uuid for specified model
         * @param[in] inputs: input image data wrapped with EVModelData format
         * @param[out] outputs: inference output wrapped with EVModelData format
         * @return false if some error occurs
         */
        bool RunInfer(const std::string& uuid, EVModelData* inputs, EVModelData* outputs);
        /**
         * @brief adpter for releasing resource
         * @param[in] uuid: uuid for specified model, the resource will be realeased
         * @return false if some error occurs
         */
        bool DestroyModel(const std::string& uuid);
        bool SetIO(EVBaseModel* p, const std::vector<std::string>& inputs, const std::vector<std::string>& outputs);

    public:        
        ~EVModelAdapter();
        static EVModelAdapter &GetAdapter();
        

    private:
        /**
         * @brief prepare lib plugins
         * @param[in] str: config file, record plugins according to config file
         */
        void Init(const std::string& str);

    private:
        std::map<std::string, ModelConfig> m_model_config{};
        std::map<std::string, EVBaseModel*> m_local_models{};
        std::map<std::string,  EVBaseModelFactory*> m_config_to_model_factory;
        std::map<EVBaseModel*, EVBaseModelFactory*> m_product_to_model_factory;
        std::map<EVBaseModel*, std::string> m_product_to_model_name;
        std::mutex m_locker;
        
};

}//end namespace ev
#endif